﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Data;
using System.Xml;
using System.ComponentModel;
using System.Collections;
using System.Data.Common;
using TN_CMS.Framework.Helper;

namespace TN_CMS.Domain.Concrete
{
    public abstract class BaseRepository
    {
        protected readonly Database _db;

        public BaseRepository()
        {
            this._db = DatabaseFactory.CreateDatabase();
        }

        protected T XmlNodeToModel<T>(XmlNode xmlNode, params string[] includePropeties)
            where T : class, new()
        {
            return (T)XmlNodeToModel(xmlNode, typeof(T), includePropeties);
        }

        protected object XmlNodeToModel(XmlNode xmlNode, Type type, params string[] includePropeties)
        {
            var model = Activator.CreateInstance(type);

            var properties = type.GetProperties();

            foreach (var property in properties)
            {
                if (property.CanWrite && (includePropeties.Length == 0 || includePropeties.Contains(property.Name)))
                {
                    if (xmlNode.Attributes[property.Name] != null)
                    {
                        var value = GetValue(xmlNode.Attributes[property.Name].Value, property.PropertyType);
                        if (value != null)
                        {
                            property.SetValue(model, value, null);
                        }
                    }
                    else
                    {
                        var childNode = xmlNode.SelectSingleNode(property.Name);
                        if (childNode != null)
                        {
                            if (property.PropertyType.IsGenericType && property.PropertyType.GetInterface("IList") != null)
                            {
                                if (childNode.ChildNodes.Count > 0)
                                {
                                    var value = (IList)Activator.CreateInstance(property.PropertyType);
                                    var itemType = property.PropertyType.GetGenericArguments()[0];
                                    foreach (XmlNode item in childNode.ChildNodes)
                                    {
                                        value.Add(XmlNodeToModel(item, itemType));
                                    }
                                    property.SetValue(model, value, null);
                                }
                            }
                            else if (childNode.ChildNodes.Count == 1)
                            {

                                var value = XmlNodeToModel(childNode.FirstChild, property.PropertyType);
                                if (value != null)
                                    property.SetValue(model, value, null);
                            }
                        }
                    }
                }
            }

            return model;
        }

        protected object GetValue(string value, Type type, params string[] properties)
        {
            if (type.IsGenericType && type.GetInterface("IList") != null)
            {
                try
                {
                    var doc = new XmlDocument();
                    doc.LoadXml(value);
                    if (doc.FirstChild.ChildNodes.Count > 0)
                    {
                        var result = (IList)Activator.CreateInstance(type);
                        var itemType = type.GetGenericArguments()[0];
                        foreach (XmlNode item in doc.FirstChild.ChildNodes)
                        {
                            result.Add(XmlNodeToModel(item, itemType, properties));
                        }
                        return result;
                    }
                    else
                        return null;
                }
                catch
                {
#if DEBUG
                    throw;
#endif
                    return null;
                }
            }

            if (TypeDescriptor.GetConverter(type).CanConvertFrom(typeof(string)))
            {
                try
                {
                    if (type.FullName == typeof(bool).FullName)
                    {
                        if (value == "1" || string.Compare(value, "True", true) == 0)
                            return true;
                        else
                            return false;
                    }

                    return CommonHelper.To(value, type);
                }
                catch
                {
#if DEBUG
                    throw;
#endif
                    return null;
                }
            }

            if (type.IsClass)
            {
                var doc = new XmlDocument();
                doc.LoadXml(value);
                return XmlNodeToModel(doc.FirstChild, type, properties);
            }

            return null;
        }

        protected T GetValue<T>(string value, params string[] properties)
            where T : new()
        {
            var type = typeof(T);
            var result = GetValue(value, type, properties);

            if (result != null)
                return (T)result;

            return default(T);
        }
    }
}
